const fs = require('fs');
const { createCanvas, loadImage } = require('canvas')

const maxSubtitleFontCount = 30 // 字幕字体最多个数
const fontSizeSubtitle = 35 // 字幕字体大小
const maxTitleFontCount = 20 // 标题字体最多个数
const fontSizeTitle = 50 // 标题字体大小
const lineSplitSubtitle = 7
const colorDefault = '#045ff8'

/**
 * 文字位于图片中央
 */
function getTxtTitlePosition(width, height, txt) {
    const txts = []
    while (txt.length > maxTitleFontCount) {
        txts.push(txt.substr(0,maxTitleFontCount))
        txt = txt.substr(maxTitleFontCount)
    }
    if (txt.length <= 2 && txts.length > 0) {
        txts[txts.length - 1] = txts[txts.length - 1] + txt
    } else {
        txts.push(txt)
    }

    // 避免ascii折行
    for(let i=1; i<txts.length; i++) {
        while(txts[i].charCodeAt(0) < 128){
            txts[i-1] = txts[i-1] + txts[i].substr(0,1);
            txts[i] = txts[i].substr(1)
        }
    }

    const x = (width - getStrSize(txts[0]) * fontSizeTitle) / 2
    const y = (height - fontSizeTitle * txts.length - lineSplitSubtitle * 2 * (txts.length - 1)) / 2
    return { size: fontSizeTitle, x, y, txts, split: lineSplitSubtitle * 2}
}


/**
 * 文字位于底部
 * 应考虑折行
 * 一行最多25字
 */
function getTxtSubTitlePosition(width, height, txt) {
    const txts = []
    while (txt.length > maxSubtitleFontCount) {
        txts.push(txt.substr(0,maxSubtitleFontCount))
        txt = txt.substr(maxSubtitleFontCount)
    }
    if (txt.length <= 2 && txts.length > 0) {
        txts[txts.length - 1] = txts[txts.length - 1] + txt
    } else {
        txts.push(txt)
    }

    // 避免ascii折行
    for(let i=1; i<txts.length; i++) {
        while(txts[i].charCodeAt(0) < 128){
            txts[i-1] = txts[i-1] + txts[i].substr(0,1);
            txts[i] = txts[i].substr(1)
        }
    }
    if (txts.length > 1 && txts[txts.length - 1].length <= 2) {
        txts[txts.length - 2] += txts[txts.length - 1];
        txts.splice(txts.length -1, 1)
    }

    const x = (width - getStrSize(txts[0]) * fontSizeSubtitle) / 2
    const y = height + 20 - fontSizeSubtitle * txts.length - lineSplitSubtitle * (txts.length - 1)
    return { size: fontSizeSubtitle, x, y, txts, split: lineSplitSubtitle}
}

/**
 * 获取字符串文字个数，ascii算0.5个
 */
function getStrSize(str) {
    let length = 0;
    for(let i=0; i<str.length; i++){
        if(str.charCodeAt(i) < 128) {
            length += 0.5
        } else {
            length += 1
        }
    }
    return Math.round(length)
}

/**
 * 取双字节字符个长度的substr，单字节算0.5个
 */
function getSubStr(str, start, len) {
    let currLen = 0;
    let i = start;
    for(; i<str.length; i++) {
        if(str.charCodeAt(i) < 128)
            currLen += 0.5;
        else
            currLen += 1;
        if (currLen >= len)
            break;
    }
    let str1 = str.substr(start, i-start+1);
    let str2 = str.substr(i+1);
    while (true) {
        if (!str2.substr(0,1).match(/\s/) && (str2.charCodeAt(0) < 128 || str2.substr(0,1) === '，')) {
            str1 += str2.substr(0, 1);
            str2 = str2.substr(1);
        } else {
            break;
        }
    }
    return str1;
}

/**
 * 生成每一帧图片：
 *   数据（帧率、当前帧、此场景总帧）目标（宽度、高度、路径） 1、背景图（源图-无源图使用蓝色背景）；2、图表（前1s后1s不显示，无pass）；3、底部字幕（无pass）4、跳动文字（前20帧后开始陆续显示->每0.5s显示1个字，无pass）5、首屏文字（无pass）
 *   {lv, currLv, totalLv, destPath, width, height, bgImg, imgChartBg, imgChart, subtitle, summary, first: {...}}
 *   TODO rgba透明度？
 */
async function makePic(data) {
    const { destPath, width, height, bgImg, imgChart, imgChartBg, subtitle, beng, summary, is_first, is_last, title, date, company, analyst } = data;
    // console.log(JSON.stringify(data))
    // console.log(destPath, width, height, bgImg, imgChart!=null, imgChartBg!=null, subtitle, summary, is_first, is_last, title, date, company, analyst);
    const canvas = createCanvas(width, height);
    const ctx = canvas.getContext('2d');
    // 背景
    if (bgImg) {
        const img = await loadImage(bgImg);
        ctx.drawImage(img, 0, 0, width, height);
    } else {
        ctx.fillStyle = colorDefault; // 默认蓝背景
        ctx.fillRect(0,0, width, height);
    }
    // 字幕
    if (!summary) {
        writeSubtitle(ctx, subtitle, width, height);
    }
    // 杂项
    writeCenterTxt(ctx, {title, date, company, analyst}, width, height);

    // // 图表 TODO 暂时使用视频上盖图表的方式
    // if (imgChart != null) {
    //     const chartWidth = width * 0.8;
    //     const chartHeight = chartWidth * 2/3;
    //     ctx.drawImage(imgChartBg,(width-chartWidth)/2,(height-chartHeight)/2,chartWidth,chartHeight);
    //     ctx.drawImage(imgChart,(width-chartWidth)/2,(height-chartHeight)/2,chartWidth,chartHeight);
    // }
    // 蹦字 beng, summary
    // console.log(beng, summary, 1)
    writeBengTxt(ctx, beng, summary, width, height);

    canvas.createJPEGStream().pipe(fs.createWriteStream(destPath)) // 生成本地图片(指定文件名)
}

function writeSubtitle(ctx, subtitle, width, height) {
    // 字幕文件
    if (subtitle) {
        const fontOptions = getTxtSubTitlePosition(width, height, subtitle)
        // 蓝底 #045ff8
        ctx.fillStyle = colorDefault;
        ctx.fillRect(0,fontOptions.y - lineSplitSubtitle - fontSizeSubtitle, width, height - (fontOptions.y - lineSplitSubtitle - fontSizeSubtitle));
        ctx.fillStyle = '#ffffff'
        ctx.font = fontOptions.size + 'px 微软雅黑'
        // 多行
        for(let i=0; i<fontOptions.txts.length; i++) {
            ctx.fillStyle = '#ffffff'
            ctx.fillText(fontOptions.txts[i], fontOptions.x, fontOptions.y + i*(fontOptions.size + fontOptions.split))
        }
    }
}
function writeCenterTxt(ctx, data, width, height) {
    const {title, date, company, analyst} = data;
    if (!title && !date && !company && !analyst) return;
    ctx.fillStyle = '#ffffff';
    let split = 50;
    let x = 800;
    let y = 0;
    let title1 = '';
    let title2 = '';
    if (title.length > 20) {
        title1 = title.substr(0,  Math.ceil(title.length / 2));
        title2 = title.substr(Math.ceil(title.length / 2));
    } else {
        title1 = title;
        title2 = '';
    }
    let fontSize = 50;
    if (title1) {
        ctx.font = fontSize + 'px 黑体'
        y = (height-fontSize)/2;
        if (title2) {
            y -= (fontSize + split)
        }
        ctx.fillText(title1, (width - title1.length * fontSize)/2, y)
        if (title2) {
            y += split * 1.5
        } else {
            y += 3*split
        }
    }
    if (title2) {
        ctx.font = fontSize + 'px 黑体'
        ctx.fillText(title2, (width - title1.length * fontSize)/2, y)
        y += 3*split
    }
    fontSize = 30;
    if (company) {
        ctx.font = fontSize + 'px 黑体'
        ctx.fillText(company, x, y)
        y += split
    }
    if (analyst) {
        ctx.font = fontSize + 'px 黑体'
        ctx.fillText(analyst, x, y)
        y += split
    }
    if (date) {
        ctx.font = fontSize + 'px 黑体'
        ctx.fillText(date, x, y)
        y += split
    }
}
function writeBengTxt(ctx, beng, summary, width, height) {
    if (!beng) return;
    const fontSize = 50;
    const strSize = getStrSize(summary);
    const lineNum = Math.ceil(strSize / 15);

    const split = 20;

    const lines = []
    let tmpTxt = summary;
    while(tmpTxt !== '') {
        const line = getSubStr(tmpTxt, 0, 15);
        tmpTxt = tmpTxt.substr(line.length);
        lines.push(line);
    }

    // 蓝色半透明背景
    ctx.font = fontSize + 'px 黑体'
    let bgWidth = 0;
    for (let i=0; i<lines.length; i++) {
        let txtwidth = ctx.measureText(lines[i]).width;
        // console.log(txtwidth, lines[i])
        if(txtwidth > bgWidth)
            bgWidth = txtwidth;
    }
    bgWidth += 2 * fontSize
    let bgHeight = (lines.length + 2) * fontSize + (lines.length - 1) * split
    ctx.fillStyle = 'rgba(4, 95, 248, 0.7)'; // 默认蓝背景
    ctx.fillRect((width - bgWidth)/2, (height - bgHeight)/2, bgWidth, bgHeight);

    let x = (width - bgWidth) / 2 + fontSize;
    let y = (height - bgHeight) / 2 + fontSize * 1.5;

    // // 设置文字阴影的颜色为黑色，透明度为20%
    // ctx.shadowColor = 'rgba(255, 255, 0, 1)';
    // // 将阴影向右移动15px，向上移动10px
    // ctx.shadowOffsetX = 0;
    // ctx.shadowOffsetY = 0;
    // // 轻微模糊阴影
    // ctx.shadowBlur = 10;

    ctx.fillStyle = '#ffffff';

    // ctx.strokeStyle = "#000000";

    for(let i=0; i<lines.length; i++) {
        const line = lines[i];
        if (beng === '')
            break;
        let txt = '';
        if (beng.indexOf(line) === 0) {
            txt = line;
            beng = beng.substr(line.length);
        } else {
            txt = beng;
            beng = '';
        }
        ctx.fillText(txt, x, y)
        // ctx.strokeText(txt, x, y);
        y += split + fontSize;
    }
}

async function test() {
    const canvas = createCanvas(1280, 720);
    const ctx = canvas.getContext('2d');
    ctx.fillStyle = colorDefault; // 默认蓝背景
    ctx.fillRect(0,0, 1280, 720);

    writeBengTxt(ctx, '预计公司2020-22年的归母净利润为51.21 / 60.82', '预计公司2020-22年的归母净利润为51.21 / 60.82 / 73.93亿元，对应的EPS为1.88 / 2.23 / 2.71元', 1280, 720)
    canvas.createJPEGStream().pipe(fs.createWriteStream('1.jpg')) // 生成本地图片(指定文件名)
}

module.exports = { makePic, test };
